The diprate R package

You can install the diprate R package by following the instructions here: https://github.com/QuLab-VU/dipDRC

Combining VLW001 and VLW_V23b datasets

After having fixed the apparent error due to incorrect assignment of missed/temporary barcodes, the VLW001 dataset looks appropriately clean for combining with the VLW_V23b dataset to enable analysis of all four cell line simultaneously and consider analyzing the 3D data.

require(diprate)
Loading required package: diprate
source("../functions/namingStandards.r")
keep_cols <- c(std_colnames,c("ch2.pos","orig.cell.count","file_name"))
d1 <- read.csv("../data/VLW001_dataset.csv", as.is=TRUE)
d2 <- read.csv("../data/VLW_V23b_dataset.csv", as.is=TRUE)
d <- merge(d1,d2, all=TRUE)

Standardize data

The VLW001 dataset did not have a calculation for viable cells (cell.count - ch2.pos) and several data types with NA values.

Steps to perform:

  • Remove extra columns
  • Calculate viable cells (cell.count <- orig.cell.count - ch2.pos)
  • Replace NA in drug1 as control and drug1.conc as 0
  • Calculate fraction of dead cells (dead.cell.frxn <- ch2.pos/orig.cell.count)
  • Identify high-density culture (confluence) and remove time points once reached
d[is.na(d$orig.cell.count),'orig.cell.count'] <- d[is.na(d$orig.cell.count),'cell.count']
cc <- d[d$orig.cell.count==d$cell.count,'cell.count'] - 
    d[d$orig.cell.count==d$cell.count,'ch2.pos']
d[d$orig.cell.count==d$cell.count & !is.na(d$cell.count),'cell.count'] <- cc[!is.na(cc)]
rm(cc)
d <- d[,keep_cols]
d[is.na(d$drug1.conc),'drug1.conc'] <- 0
d[is.na(d$drug1),'drug1'] <- 'control'
d <- d[!is.na(d$cell.count),]
d$drug1.units <- 'M'
d <- d[order(d$plate.name,d$uid,d$time),]
d$cell.count[d$cell.count<=0] <- 1

rownames(d) <- NULL

Modified from VLW_V23b_analysis.Rmd
Should exclude wells O14–O20 on drug plate 3 since it appears they really contain drugs.

d <- d[!(d$well %in% paste0('O',14:20) & grepl("-D3", d$plate.name)),]

Subset 2D cultures only.

a <- d[grepl("^V2", d$plate.name),]

Perform QC on controls.

par(mfrow=c(2,2))
ctrl <- sapply(unique(a$cell.line), function(cl) {
    controlQC(  a[a$cell.line==cl & a$drug1.conc==0,]$time,
                a[a$cell.line==cl & a$drug1.conc==0,]$cell.count,
                a[a$cell.line==cl & a$drug1.conc==0,]$uid,
                cell.line.name=cl,
                min.ar2=0.95,
                plotIt=TRUE,
                ret.type="all")
    }, simplify=FALSE)

Determine maximum number of cells consistent with exponential growth.

max.counts <- sapply(unique(a$cell.line), function(cl) {
    findMaxCounts(  a[a$cell.line==cl & a$drug1.conc==0,]$time,
                a[a$cell.line==cl & a$drug1.conc==0,]$cell.count,
                a[a$cell.line==cl & a$drug1.conc==0,]$uid,
                min.ar2=0.95)}, 
    simplify=FALSE)
The first 5 pts of ids = V2-11T-D1_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-11T-D1_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-11T-D1_O21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-11T-D2_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_C02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_E02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_E13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_F13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_G13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_H02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_I14 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_I15 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_I16 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_I21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_J13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D2_O13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_B13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_D02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_E02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_E13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_F13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_G02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_G13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_I13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_J02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_J13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_K02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_L02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_M13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_O02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_O13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_O21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_O22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D3_O23 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_B13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_C02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_D02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_E02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_E13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_F02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_F13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_G02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_G13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_H02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I14 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I16 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I17 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I18 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I19 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I20 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_I23 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_J02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_J13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_K02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_L02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_M02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_M13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_O02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D4_O13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_B13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_C02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_D02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_E02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_E13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_F02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_F13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_G02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_G13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_H02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_I13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_J02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_J13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_K02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L14 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L15 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L16 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L17 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L18 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L19 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L20 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_L23 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_M02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_M13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_O02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-16T-D5_O13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_B02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_F02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_G02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_H02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_J02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_J13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_K02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_L02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_M13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_O15 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_O16 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_O18 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_O20 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D1_O22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D2_I18 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D2_I22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D3_G13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D3_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D3_I13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D3_O22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D4_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D4_D02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-21T-D4_I22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_B13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_C02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_C13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_D02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_E02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_E13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_G02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_H02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_I02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_I13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_J02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_K02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_L02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_M02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_M13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_N02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O02 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O14 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O19 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O20 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D1_O21 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_B13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_D13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_I16 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_I22 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_K13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D2_N13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D3_H13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D4_L13 is not linear within ar2 = 0.95
The first 5 pts of ids = V2-29T-D4_M02 is not linear within ar2 = 0.95

Show histogram of max counts for each cell line.

par(mfrow=c(1,4))
invisible(lapply(names(max.counts), function(n) boxplot(max.counts[[n]]$max.exp.counts, ylim=c(0,2000), main=n)))

QC of 16T data

Appears that cells are reaching confluence during the experiment only for 16T. Identify the max counts where growth has not yet been restricted and use to obtain a reasonable max value to limit data.

Remove data from 16T when cell count exceeds the max consistent with exponential growth in the control wells.

max.16T <- quantile(max.counts[['16T']]$max.exp.counts, 0.05)
uid2filter <- unique(d[d$cell.count>max.16T,'uid'])
times2filter <- sapply(uid2filter, function(id) min(d[d$uid==id & d$cell.count>max.16T,'time']))

b <- d[d$uid %in% uid2filter,]
b <- do.call(rbind, lapply(seq_along(uid2filter), function(i) 
    b[b$uid==uid2filter[i] & b$time <times2filter[i],]))

d <- d[!d$uid %in% uid2filter,]
d <- rbind(d,b)
d <- d[order(d$plate.name,d$uid,d$time),]
a <- d[grepl("^V2", d$plate.name),]
par(mfcol=c(5,4))
invisible(lapply(unique(a$plate.name), function(mypn) do.call(plotGC,append(
    list(ylim=c(0,5), main=mypn, leg=FALSE),getGCargs(a[a$plate.name==mypn & a$drug1.conc==0,])))))

Remove bad controls

Use a 95% confidence interval to determine which wells may be outliers. Use code in controlQC function in diprate package.

ctrl_ids <- unique(a[a$drug1.conc==0,'uid'])

ctrlQC <- function(dat)
{
    ids <- as.character(unique(dat$uid))
    
    m <- lm(log2(cell.count) ~ time * uid, data=dat)
    rates <- coef(m)[grepl("time", names(coef(m)))]
    rates <- c(rates[1], rates[-1] + rates[1])
    ids.ok <- names(rates[rates < mean(rates) + sd(rates) & rates > 
        mean(rates) - sd(rates)])
    ids.ok <- gsub("time:uid", "", ids.ok)
    ids.ok <- sub("time", ids[1], ids.ok)
    out <- list(good_controls=ids.ok, outliers=setdiff(ids,ids.ok))
    return(out)
}

Assess controls and remove outliers from data.

ctrl_quality <- lapply(unique(a$cell.line), function(cl) ctrlQC(a[a$cell.line==cl & a$drug1.conc==0,]))
bad_ctrls <- unlist(sapply(ctrl_quality, '[[', 'outliers'))
d <- d[!d$uid %in% bad_ctrls,]
a <- d[grepl("^V2", d$plate.name),]
par(mfcol=c(5,4))
invisible(lapply(unique(a$plate.name), function(mypn) do.call(plotGC,append(
    list(ylim=c(0,5), main=mypn, leg=FALSE),getGCargs(a[a$plate.name==mypn & a$drug1.conc==0,])))))

Examine growth curves

Use a single drug to assess growth curves across all drug concentrations for each cell line.

par(mfrow=c(1,4))
invisible(lapply(unique(a[a$drug1=="VU0823511", 'plate.name']), function(pn) do.call(plotGC,append(
    list(ylim=c(-2,5), main=pn, leg=FALSE),getGCargs(a[a$plate.name==pn & a$drug1=="VU0823511",])))))

Replace drug names

Obtained, from Dave Westover, drug names to replace VU-specific identifiers.

new_drug_names <- readxl::read_xlsx("../data/VLW001_full_drugnames.xlsx")

Plan is to replace drug names by matching d$drug1 to new_drug_names$VU_ID and replace with new_drug_names$"Chemical Name". However, the chemical names need to be cleaned.

new_drugs <- as.character(new_drug_names$"Chemical Name")

Algorithm:

  • split on (, keeping first part.
  • remove dashes
  • remove spaces if before numbers
  • split on spaces, keeping first part (remove salts)
  • If only first letter cap or if != “Ro”, make lowercase
temp <- sapply(strsplit(new_drugs, " (", fixed=TRUE), "[[", 1, simplify=TRUE)
temp[grep(" [0-9]",temp)] <- gsub(" ", "", temp[grep(" [0-9]",temp)])
temp <- gsub("-", "", temp)
temp <- sapply(strsplit(temp, " "), "[[", 1, simplify=TRUE)
temp[!grepl("Ro", temp) & grepl("^[A-Z][a-z]", temp)] <- 
    tolower(temp[!grepl("Ro", temp) & grepl("^[A-Z][a-z]", temp)])
new_drug_names$drug1 <- temp

Replace d$drug1 values starting with VU with appropriate value in new_drug_names$drug1 then subset data for 2D data only and save into object a.

Exclude file_name from Thunor data.

d[grep("^VU",d$drug1), 'drug1'] <- 
    new_drug_names[match(d[grep("^VU",d$drug1),'drug1'], new_drug_names$VU_ID),]$drug1

a <- d[grepl("^V2", d$plate.name),]
a <- a[,colnames(a)!="file_name"]

Save 2D data for Thunor

OVERWRITE <- FALSE
thunor_2D_dat <- a
thunor_2D_dat$upid <- paste(thunor_2D_dat$expt.date, thunor_2D_dat$plate.name, sep='_')
thunor_2D_dat$drug1.units <- 'M'
thunor_fn <- "../data/VLW_V23ab_2Donly_Thunor_dataset.csv"
if(!file.exists(thunor_fn) | OVERWRITE) write.csv(thunor_2D_dat, file=thunor_fn, row.names=FALSE)

Save all data (including file name with full path)

alldat_fn <- "../data/VLW_V23ab_dataset.csv"
if(!file.exists(alldat_fn) | OVERWRITE) write.csv(d, file=alldat_fn, row.names=FALSE)
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgVkxXIDJEdnMzRCBjb21iaW5lZCBkYXRhIgpvdXRwdXQ6IAogICAgaHRtbF9ub3RlYm9vazoKICAgICAgICBzZWxmX2NvbnRhaW5lZDogeWVzCmF1dGhvcjogIkRhcnJlbiBSIFR5c29uIgpkYXRlOiAiMjAyMC0xMS0xNyIKLS0tCgojIyBUaGUgYGRpcHJhdGVgIFIgcGFja2FnZQpZb3UgY2FuIGluc3RhbGwgdGhlIGBkaXByYXRlYCBSIHBhY2thZ2UgYnkgZm9sbG93aW5nIHRoZSBpbnN0cnVjdGlvbnMgaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL1F1TGFiLVZVL2RpcERSQyAgCgoKIyMjIENvbWJpbmluZyBWTFcwMDEgYW5kIFZMV19WMjNiIGRhdGFzZXRzCkFmdGVyIGhhdmluZyBmaXhlZCB0aGUgYXBwYXJlbnQgZXJyb3IgZHVlIHRvIGluY29ycmVjdCBhc3NpZ25tZW50IG9mIG1pc3NlZC90ZW1wb3JhcnkgYmFyY29kZXMsIHRoZSBWTFcwMDEgZGF0YXNldCBsb29rcyBhcHByb3ByaWF0ZWx5IGNsZWFuIGZvciBjb21iaW5pbmcgd2l0aCB0aGUgVkxXX1YyM2IgZGF0YXNldCB0byBlbmFibGUgYW5hbHlzaXMgb2YgYWxsIGZvdXIgY2VsbCBsaW5lIHNpbXVsdGFuZW91c2x5IGFuZCBjb25zaWRlciBhbmFseXppbmcgdGhlIDNEIGRhdGEuCgpgYGB7ciBTZXR1cH0KcmVxdWlyZShkaXByYXRlKQpzb3VyY2UoIi4uL2Z1bmN0aW9ucy9uYW1pbmdTdGFuZGFyZHMuciIpCmtlZXBfY29scyA8LSBjKHN0ZF9jb2xuYW1lcyxjKCJjaDIucG9zIiwib3JpZy5jZWxsLmNvdW50IiwiZmlsZV9uYW1lIikpCmBgYAoKYGBge3IgTG9hZCBkYXRhfQpkMSA8LSByZWFkLmNzdigiLi4vZGF0YS9WTFcwMDFfZGF0YXNldC5jc3YiLCBhcy5pcz1UUlVFKQpkMiA8LSByZWFkLmNzdigiLi4vZGF0YS9WTFdfVjIzYl9kYXRhc2V0LmNzdiIsIGFzLmlzPVRSVUUpCmQgPC0gbWVyZ2UoZDEsZDIsIGFsbD1UUlVFKQpgYGAKCgojIyMjIFN0YW5kYXJkaXplIGRhdGEKVGhlIFZMVzAwMSBkYXRhc2V0IGRpZCBub3QgaGF2ZSBhIGNhbGN1bGF0aW9uIGZvciB2aWFibGUgY2VsbHMgKGBjZWxsLmNvdW50IC0gY2gyLnBvc2ApIGFuZCBzZXZlcmFsIGRhdGEgdHlwZXMgd2l0aCBOQSB2YWx1ZXMuCgpTdGVwcyB0byBwZXJmb3JtOiAgCgoqIFJlbW92ZSBleHRyYSBjb2x1bW5zCiogQ2FsY3VsYXRlIHZpYWJsZSBjZWxscyAoYGNlbGwuY291bnQgPC0gb3JpZy5jZWxsLmNvdW50IC0gY2gyLnBvc2ApCiogUmVwbGFjZSBOQSBpbiBgZHJ1ZzFgIGFzIGBjb250cm9sYCBhbmQgYGRydWcxLmNvbmNgIGFzIGAwYAoqIENhbGN1bGF0ZSBmcmFjdGlvbiBvZiBkZWFkIGNlbGxzIChgZGVhZC5jZWxsLmZyeG4gPC0gY2gyLnBvcy9vcmlnLmNlbGwuY291bnRgKQoqIElkZW50aWZ5IGhpZ2gtZGVuc2l0eSBjdWx0dXJlIChjb25mbHVlbmNlKSBhbmQgcmVtb3ZlIHRpbWUgcG9pbnRzIG9uY2UgcmVhY2hlZAoKYGBge3IgUXVhbnRpZnkgdmlhYmxlIGNlbGxzfQpkW2lzLm5hKGQkb3JpZy5jZWxsLmNvdW50KSwnb3JpZy5jZWxsLmNvdW50J10gPC0gZFtpcy5uYShkJG9yaWcuY2VsbC5jb3VudCksJ2NlbGwuY291bnQnXQpjYyA8LSBkW2Qkb3JpZy5jZWxsLmNvdW50PT1kJGNlbGwuY291bnQsJ2NlbGwuY291bnQnXSAtIAogICAgZFtkJG9yaWcuY2VsbC5jb3VudD09ZCRjZWxsLmNvdW50LCdjaDIucG9zJ10KZFtkJG9yaWcuY2VsbC5jb3VudD09ZCRjZWxsLmNvdW50ICYgIWlzLm5hKGQkY2VsbC5jb3VudCksJ2NlbGwuY291bnQnXSA8LSBjY1shaXMubmEoY2MpXQpybShjYykKYGBgCgoKYGBge3IgUmVtb3ZlIGV4dHJhIGNvbHVtbnN9CmQgPC0gZFssa2VlcF9jb2xzXQpkW2lzLm5hKGQkZHJ1ZzEuY29uYyksJ2RydWcxLmNvbmMnXSA8LSAwCmRbaXMubmEoZCRkcnVnMSksJ2RydWcxJ10gPC0gJ2NvbnRyb2wnCmQgPC0gZFshaXMubmEoZCRjZWxsLmNvdW50KSxdCmQkZHJ1ZzEudW5pdHMgPC0gJ00nCmQgPC0gZFtvcmRlcihkJHBsYXRlLm5hbWUsZCR1aWQsZCR0aW1lKSxdCmQkY2VsbC5jb3VudFtkJGNlbGwuY291bnQ8PTBdIDwtIDEKCnJvd25hbWVzKGQpIDwtIE5VTEwKYGBgCgoqTW9kaWZpZWQgZnJvbSBgVkxXX1YyM2JfYW5hbHlzaXMuUm1kYCogIApTaG91bGQgZXhjbHVkZSB3ZWxscyBPMTTigJNPMjAgb24gZHJ1ZyBwbGF0ZSAzIHNpbmNlIGl0IGFwcGVhcnMgdGhleSByZWFsbHkgY29udGFpbiBkcnVncy4KYGBge3J9CmQgPC0gZFshKGQkd2VsbCAlaW4lIHBhc3RlMCgnTycsMTQ6MjApICYgZ3JlcGwoIi1EMyIsIGQkcGxhdGUubmFtZSkpLF0KYGBgCgpTdWJzZXQgMkQgY3VsdHVyZXMgb25seS4KYGBge3IgU3Vic2V0IDJEfQphIDwtIGRbZ3JlcGwoIl5WMiIsIGQkcGxhdGUubmFtZSksXQpgYGAKClBlcmZvcm0gUUMgb24gY29udHJvbHMuCmBgYHtyIENvbnRyb2wgUUMsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhcihtZnJvdz1jKDIsMikpCmN0cmwgPC0gc2FwcGx5KHVuaXF1ZShhJGNlbGwubGluZSksIGZ1bmN0aW9uKGNsKSB7Cgljb250cm9sUUMoCWFbYSRjZWxsLmxpbmU9PWNsICYgYSRkcnVnMS5jb25jPT0wLF0kdGltZSwKCQkJCWFbYSRjZWxsLmxpbmU9PWNsICYgYSRkcnVnMS5jb25jPT0wLF0kY2VsbC5jb3VudCwKCQkJCWFbYSRjZWxsLmxpbmU9PWNsICYgYSRkcnVnMS5jb25jPT0wLF0kdWlkLAoJCQkJY2VsbC5saW5lLm5hbWU9Y2wsCgkJCSAgICBtaW4uYXIyPTAuOTUsCgkJCQlwbG90SXQ9VFJVRSwKICAgICAgICAgICAgICAgIHJldC50eXBlPSJhbGwiKQoJfSwgc2ltcGxpZnk9RkFMU0UpCmBgYAoKRGV0ZXJtaW5lIG1heGltdW0gbnVtYmVyIG9mIGNlbGxzIGNvbnNpc3RlbnQgd2l0aCBleHBvbmVudGlhbCBncm93dGguCmBgYHtyIEdldCBtYXggY291bnRzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptYXguY291bnRzIDwtIHNhcHBseSh1bmlxdWUoYSRjZWxsLmxpbmUpLCBmdW5jdGlvbihjbCkgewoJZmluZE1heENvdW50cygJYVthJGNlbGwubGluZT09Y2wgJiBhJGRydWcxLmNvbmM9PTAsXSR0aW1lLAoJCQkJYVthJGNlbGwubGluZT09Y2wgJiBhJGRydWcxLmNvbmM9PTAsXSRjZWxsLmNvdW50LAoJCQkJYVthJGNlbGwubGluZT09Y2wgJiBhJGRydWcxLmNvbmM9PTAsXSR1aWQsCiAgICAgICAgICAgICAgICBtaW4uYXIyPTAuOTUpfSwgCglzaW1wbGlmeT1GQUxTRSkKCmBgYAoKU2hvdyBoaXN0b2dyYW0gb2YgbWF4IGNvdW50cyBmb3IgZWFjaCBjZWxsIGxpbmUuCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTh9CnBhcihtZnJvdz1jKDEsNCkpCmludmlzaWJsZShsYXBwbHkobmFtZXMobWF4LmNvdW50cyksIGZ1bmN0aW9uKG4pIGJveHBsb3QobWF4LmNvdW50c1tbbl1dJG1heC5leHAuY291bnRzLCB5bGltPWMoMCwyMDAwKSwgbWFpbj1uKSkpCmBgYAoKIyMjIyBRQyBvZiAxNlQgZGF0YQpBcHBlYXJzIHRoYXQgY2VsbHMgYXJlIHJlYWNoaW5nIGNvbmZsdWVuY2UgZHVyaW5nIHRoZSBleHBlcmltZW50IG9ubHkgZm9yIDE2VC4gSWRlbnRpZnkgdGhlIG1heCBjb3VudHMgd2hlcmUgZ3Jvd3RoIGhhcyBub3QgeWV0IGJlZW4gcmVzdHJpY3RlZCBhbmQgdXNlIHRvIG9idGFpbiBhIHJlYXNvbmFibGUgbWF4IHZhbHVlIHRvIGxpbWl0IGRhdGEuICAKClJlbW92ZSBkYXRhIGZyb20gMTZUIHdoZW4gY2VsbCBjb3VudCBleGNlZWRzIHRoZSBtYXggY29uc2lzdGVudCB3aXRoIGV4cG9uZW50aWFsIGdyb3d0aCBpbiB0aGUgY29udHJvbCB3ZWxscy4gCmBgYHtyIFJlbW92ZSBkYXRhIGFmdGVyIG1heCBjb3VudHN9Cm1heC4xNlQgPC0gcXVhbnRpbGUobWF4LmNvdW50c1tbJzE2VCddXSRtYXguZXhwLmNvdW50cywgMC4wNSkKdWlkMmZpbHRlciA8LSB1bmlxdWUoZFtkJGNlbGwuY291bnQ+bWF4LjE2VCwndWlkJ10pCnRpbWVzMmZpbHRlciA8LSBzYXBwbHkodWlkMmZpbHRlciwgZnVuY3Rpb24oaWQpIG1pbihkW2QkdWlkPT1pZCAmIGQkY2VsbC5jb3VudD5tYXguMTZULCd0aW1lJ10pKQoKYiA8LSBkW2QkdWlkICVpbiUgdWlkMmZpbHRlcixdCmIgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KHNlcV9hbG9uZyh1aWQyZmlsdGVyKSwgZnVuY3Rpb24oaSkgCiAgICBiW2IkdWlkPT11aWQyZmlsdGVyW2ldICYgYiR0aW1lIDx0aW1lczJmaWx0ZXJbaV0sXSkpCgpkIDwtIGRbIWQkdWlkICVpbiUgdWlkMmZpbHRlcixdCmQgPC0gcmJpbmQoZCxiKQpkIDwtIGRbb3JkZXIoZCRwbGF0ZS5uYW1lLGQkdWlkLGQkdGltZSksXQphIDwtIGRbZ3JlcGwoIl5WMiIsIGQkcGxhdGUubmFtZSksXQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTEsIGZpZy53aWR0aD04fQpwYXIobWZjb2w9Yyg1LDQpKQppbnZpc2libGUobGFwcGx5KHVuaXF1ZShhJHBsYXRlLm5hbWUpLCBmdW5jdGlvbihteXBuKSBkby5jYWxsKHBsb3RHQyxhcHBlbmQoCiAgICBsaXN0KHlsaW09YygwLDUpLCBtYWluPW15cG4sIGxlZz1GQUxTRSksZ2V0R0NhcmdzKGFbYSRwbGF0ZS5uYW1lPT1teXBuICYgYSRkcnVnMS5jb25jPT0wLF0pKSkpKQpgYGAKCiMjIyMgUmVtb3ZlIGJhZCBjb250cm9scwpVc2UgYSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byBkZXRlcm1pbmUgd2hpY2ggd2VsbHMgbWF5IGJlIG91dGxpZXJzLiBVc2UgY29kZSBpbiBgY29udHJvbFFDYCBmdW5jdGlvbiBpbiBgZGlwcmF0ZWAgcGFja2FnZS4KYGBge3J9CmN0cmxfaWRzIDwtIHVuaXF1ZShhW2EkZHJ1ZzEuY29uYz09MCwndWlkJ10pCgpjdHJsUUMgPC0gZnVuY3Rpb24oZGF0KQp7CiAgICBpZHMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShkYXQkdWlkKSkKICAgIAogICAgbSA8LSBsbShsb2cyKGNlbGwuY291bnQpIH4gdGltZSAqIHVpZCwgZGF0YT1kYXQpCiAgICByYXRlcyA8LSBjb2VmKG0pW2dyZXBsKCJ0aW1lIiwgbmFtZXMoY29lZihtKSkpXQogICAgcmF0ZXMgPC0gYyhyYXRlc1sxXSwgcmF0ZXNbLTFdICsgcmF0ZXNbMV0pCiAgICBpZHMub2sgPC0gbmFtZXMocmF0ZXNbcmF0ZXMgPCBtZWFuKHJhdGVzKSArIHNkKHJhdGVzKSAmIHJhdGVzID4gCiAgICAgICAgbWVhbihyYXRlcykgLSBzZChyYXRlcyldKQogICAgaWRzLm9rIDwtIGdzdWIoInRpbWU6dWlkIiwgIiIsIGlkcy5vaykKICAgIGlkcy5vayA8LSBzdWIoInRpbWUiLCBpZHNbMV0sIGlkcy5vaykKICAgIG91dCA8LSBsaXN0KGdvb2RfY29udHJvbHM9aWRzLm9rLCBvdXRsaWVycz1zZXRkaWZmKGlkcyxpZHMub2spKQogICAgcmV0dXJuKG91dCkKfQoKCmBgYAoKCkFzc2VzcyBjb250cm9scyBhbmQgcmVtb3ZlIG91dGxpZXJzIGZyb20gZGF0YS4KYGBge3J9CmN0cmxfcXVhbGl0eSA8LSBsYXBwbHkodW5pcXVlKGEkY2VsbC5saW5lKSwgZnVuY3Rpb24oY2wpIGN0cmxRQyhhW2EkY2VsbC5saW5lPT1jbCAmIGEkZHJ1ZzEuY29uYz09MCxdKSkKYmFkX2N0cmxzIDwtIHVubGlzdChzYXBwbHkoY3RybF9xdWFsaXR5LCAnW1snLCAnb3V0bGllcnMnKSkKZCA8LSBkWyFkJHVpZCAlaW4lIGJhZF9jdHJscyxdCmEgPC0gZFtncmVwbCgiXlYyIiwgZCRwbGF0ZS5uYW1lKSxdCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xMSwgZmlnLndpZHRoPTh9CnBhcihtZmNvbD1jKDUsNCkpCmludmlzaWJsZShsYXBwbHkodW5pcXVlKGEkcGxhdGUubmFtZSksIGZ1bmN0aW9uKG15cG4pIGRvLmNhbGwocGxvdEdDLGFwcGVuZCgKICAgIGxpc3QoeWxpbT1jKDAsNSksIG1haW49bXlwbiwgbGVnPUZBTFNFKSxnZXRHQ2FyZ3MoYVthJHBsYXRlLm5hbWU9PW15cG4gJiBhJGRydWcxLmNvbmM9PTAsXSkpKSkpCmBgYAoKIyMjIyBFeGFtaW5lIGdyb3d0aCBjdXJ2ZXMKVXNlIGEgc2luZ2xlIGRydWcgdG8gYXNzZXNzIGdyb3d0aCBjdXJ2ZXMgYWNyb3NzIGFsbCBkcnVnIGNvbmNlbnRyYXRpb25zIGZvciBlYWNoIGNlbGwgbGluZS4KYGBge3IgQ2hlY2sgZHJ1ZyBRQywgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9OH0KcGFyKG1mcm93PWMoMSw0KSkKaW52aXNpYmxlKGxhcHBseSh1bmlxdWUoYVthJGRydWcxPT0iVlUwODIzNTExIiwgJ3BsYXRlLm5hbWUnXSksIGZ1bmN0aW9uKHBuKSBkby5jYWxsKHBsb3RHQyxhcHBlbmQoCiAgICBsaXN0KHlsaW09YygtMiw1KSwgbWFpbj1wbiwgbGVnPUZBTFNFKSxnZXRHQ2FyZ3MoYVthJHBsYXRlLm5hbWU9PXBuICYgYSRkcnVnMT09IlZVMDgyMzUxMSIsXSkpKSkpCmBgYAoKIyMjIyBSZXBsYWNlIGRydWcgbmFtZXMKT2J0YWluZWQsIGZyb20gRGF2ZSBXZXN0b3ZlciwgZHJ1ZyBuYW1lcyB0byByZXBsYWNlIFZVLXNwZWNpZmljIGlkZW50aWZpZXJzLiAKCmBgYHtyfQpuZXdfZHJ1Z19uYW1lcyA8LSByZWFkeGw6OnJlYWRfeGxzeCgiLi4vZGF0YS9WTFcwMDFfZnVsbF9kcnVnbmFtZXMueGxzeCIpCmBgYAoKUGxhbiBpcyB0byByZXBsYWNlIGRydWcgbmFtZXMgYnkgbWF0Y2hpbmcgYGQkZHJ1ZzFgIHRvIGBuZXdfZHJ1Z19uYW1lcyRWVV9JRGAgYW5kIHJlcGxhY2Ugd2l0aCBgbmV3X2RydWdfbmFtZXMkIkNoZW1pY2FsIE5hbWUiYC4gSG93ZXZlciwgdGhlIGNoZW1pY2FsIG5hbWVzIG5lZWQgdG8gYmUgY2xlYW5lZC4KCmBgYHtyfQpuZXdfZHJ1Z3MgPC0gYXMuY2hhcmFjdGVyKG5ld19kcnVnX25hbWVzJCJDaGVtaWNhbCBOYW1lIikKYGBgCgpBbGdvcml0aG06CgoqIHNwbGl0IG9uIGAoYCwga2VlcGluZyBmaXJzdCBwYXJ0LgoqIHJlbW92ZSBkYXNoZXMKKiByZW1vdmUgc3BhY2VzIGlmIGJlZm9yZSBudW1iZXJzCiogc3BsaXQgb24gc3BhY2VzLCBrZWVwaW5nIGZpcnN0IHBhcnQgKHJlbW92ZSBzYWx0cykKKiBJZiBvbmx5IGZpcnN0IGxldHRlciBjYXAgb3IgaWYgIT0gIlJvIiwgbWFrZSBsb3dlcmNhc2UKCmBgYHtyfQp0ZW1wIDwtIHNhcHBseShzdHJzcGxpdChuZXdfZHJ1Z3MsICIgKCIsIGZpeGVkPVRSVUUpLCAiW1siLCAxLCBzaW1wbGlmeT1UUlVFKQp0ZW1wW2dyZXAoIiBbMC05XSIsdGVtcCldIDwtIGdzdWIoIiAiLCAiIiwgdGVtcFtncmVwKCIgWzAtOV0iLHRlbXApXSkKdGVtcCA8LSBnc3ViKCItIiwgIiIsIHRlbXApCnRlbXAgPC0gc2FwcGx5KHN0cnNwbGl0KHRlbXAsICIgIiksICJbWyIsIDEsIHNpbXBsaWZ5PVRSVUUpCnRlbXBbIWdyZXBsKCJSbyIsIHRlbXApICYgZ3JlcGwoIl5bQS1aXVthLXpdIiwgdGVtcCldIDwtIAogICAgdG9sb3dlcih0ZW1wWyFncmVwbCgiUm8iLCB0ZW1wKSAmIGdyZXBsKCJeW0EtWl1bYS16XSIsIHRlbXApXSkKbmV3X2RydWdfbmFtZXMkZHJ1ZzEgPC0gdGVtcApgYGAKClJlcGxhY2UgYGQkZHJ1ZzFgIHZhbHVlcyBzdGFydGluZyB3aXRoIGBWVWAgd2l0aCBhcHByb3ByaWF0ZSB2YWx1ZSBpbiBgbmV3X2RydWdfbmFtZXMkZHJ1ZzFgIHRoZW4gc3Vic2V0IGRhdGEgZm9yIDJEIGRhdGEgb25seSBhbmQgc2F2ZSBpbnRvIG9iamVjdCBgYWAuIAoKRXhjbHVkZSBgZmlsZV9uYW1lYCBmcm9tIFRodW5vciBkYXRhLgpgYGB7cn0KZFtncmVwKCJeVlUiLGQkZHJ1ZzEpLCAnZHJ1ZzEnXSA8LSAKICAgIG5ld19kcnVnX25hbWVzW21hdGNoKGRbZ3JlcCgiXlZVIixkJGRydWcxKSwnZHJ1ZzEnXSwgbmV3X2RydWdfbmFtZXMkVlVfSUQpLF0kZHJ1ZzEKCmEgPC0gZFtncmVwbCgiXlYyIiwgZCRwbGF0ZS5uYW1lKSxdCmEgPC0gYVssY29sbmFtZXMoYSkhPSJmaWxlX25hbWUiXQpgYGAKCiMjIyMgU2F2ZSAyRCBkYXRhIGZvciBUaHVub3IKCmBgYHtyfQpPVkVSV1JJVEUgPC0gRkFMU0UKdGh1bm9yXzJEX2RhdCA8LSBhCnRodW5vcl8yRF9kYXQkdXBpZCA8LSBwYXN0ZSh0aHVub3JfMkRfZGF0JGV4cHQuZGF0ZSwgdGh1bm9yXzJEX2RhdCRwbGF0ZS5uYW1lLCBzZXA9J18nKQp0aHVub3JfMkRfZGF0JGRydWcxLnVuaXRzIDwtICdNJwp0aHVub3JfZm4gPC0gIi4uL2RhdGEvVkxXX1YyM2FiXzJEb25seV9UaHVub3JfZGF0YXNldC5jc3YiCmlmKCFmaWxlLmV4aXN0cyh0aHVub3JfZm4pIHwgT1ZFUldSSVRFKSB3cml0ZS5jc3YodGh1bm9yXzJEX2RhdCwgZmlsZT10aHVub3JfZm4sIHJvdy5uYW1lcz1GQUxTRSkKYGBgCgojIyMjIFNhdmUgYWxsIGRhdGEgKGluY2x1ZGluZyBmaWxlIG5hbWUgd2l0aCBmdWxsIHBhdGgpCgpgYGB7cn0KYWxsZGF0X2ZuIDwtICIuLi9kYXRhL1ZMV19WMjNhYl9kYXRhc2V0LmNzdiIKaWYoIWZpbGUuZXhpc3RzKGFsbGRhdF9mbikgfCBPVkVSV1JJVEUpIHdyaXRlLmNzdihkLCBmaWxlPWFsbGRhdF9mbiwgcm93Lm5hbWVzPUZBTFNFKQpgYGAKCg==